/*
 * Copyright (c) 2006-2023, RT-Thread Development Team
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 * 2022-06-29     Rbb666       first version
 */

#include <rtthread.h>
#include <rtdevice.h>
#include "cycfg_capsense.h"

#include "drv_gpio.h"
#include "drv_usbd.h"

#define LED_PIN     GET_PIN(0, 0)

#define CAPSENSE_INTR_PRIORITY      (7u)

static rt_sem_t trans_done_semphr = RT_NULL;
static rt_thread_t sld_thread = RT_NULL;

static void capsense_isr(void)
{
    /* enter interrupt */
    rt_interrupt_enter();

    Cy_CapSense_InterruptHandler(CYBSP_CSD_HW, &cy_capsense_context);

    /* leave interrupt */
    rt_interrupt_leave();
}

void capsense_callback(cy_stc_active_scan_sns_t *ptrActiveScan)
{
    rt_sem_release(trans_done_semphr);
}

static uint32_t initialize_capsense(void)
{
    uint32_t status = CYRET_SUCCESS;

    /* CapSense interrupt configuration parameters */
    static const cy_stc_sysint_t capSense_intr_config =
    {
        .intrSrc = csd_interrupt_IRQn,
        .intrPriority = CAPSENSE_INTR_PRIORITY,
    };

    /* Capture the CSD HW block and initialize it to the default state. */
    status = Cy_CapSense_Init(&cy_capsense_context);
    if (CYRET_SUCCESS != status)
    {
        return status;
    }

    /* Initialize CapSense interrupt */
    cyhal_system_set_isr(csd_interrupt_IRQn, csd_interrupt_IRQn, CAPSENSE_INTR_PRIORITY, &capsense_isr);
    NVIC_ClearPendingIRQ(capSense_intr_config.intrSrc);
    NVIC_EnableIRQ(capSense_intr_config.intrSrc);

    /* Initialize the CapSense firmware modules. */
    status = Cy_CapSense_Enable(&cy_capsense_context);
    if (CYRET_SUCCESS != status)
    {
        return status;
    }

    /* Assign a callback function to indicate end of CapSense scan. */
    status = Cy_CapSense_RegisterCallback(CY_CAPSENSE_END_OF_SCAN_E,
                                          capsense_callback, &cy_capsense_context);
    if (CYRET_SUCCESS != status)
    {
        return status;
    }

    return status;
}

void Slider_Init(void)
{
    cy_rslt_t result;

    result = initialize_capsense();

    if (CYRET_SUCCESS != result)
    {
        /* Halt the CPU if CapSense initialization failed */
        RT_ASSERT(0);
    }

    /* Initiate first scan */
    Cy_CapSense_ScanAllWidgets(&cy_capsense_context);

    trans_done_semphr = rt_sem_create("slider_sem", 1, RT_IPC_FLAG_PRIO);
    if (trans_done_semphr == RT_NULL)
    {
        rt_kprintf("create transform done semphr failed.\n");
        RT_ASSERT(0);
        return;
    }
}

#define HID_MEDIA_NULL        0x00U
#define HID_MEDIA_AUDIO_NEXT  0x01U
#define HID_MEDIA_AUDIO_PREV  0x02U
#define HID_MEDIA_AUDIO_STOP  0x04U
#define HID_MEDIA_AUDIO_PLAY_PAUSE  0x08U
#define HID_MEDIA_AUDIO_MUTE  0x10U
#define HID_MEDIA_AUDIO_VOLUME_UP 0x20U
#define HID_MEDIA_AUDIO_VOLUME_DOWN 0x40U
#define HID_MEDIA_AUDIO_INPUT 0x80U
void send_hid_media_cmd(uint8_t cmd)
{
    rt_device_t usbd0 = RT_NULL;

    usbd0 = rt_device_find("hidd");
    if (usbd0)
        rt_device_open(usbd0, RT_DEVICE_FLAG_RDWR);
    else

    rt_thread_mdelay(2);
    rt_device_write(usbd0, HID_REPORT_ID_MEDIA, &cmd, 1);

    cmd = HID_MEDIA_NULL;
    rt_device_write(usbd0, HID_REPORT_ID_MEDIA, &cmd, 1);

    rt_device_close(usbd0);

    return;
}


static void process_touch(void)
{
    cy_stc_capsense_touch_t *slider_touch_info;
    uint16_t slider_pos;
    uint8_t slider_touch_status;
    uint8_t send_cmd;

    static uint16_t slider_pos_prev;
    static rt_tick_t lastMsgTick;

    /* Get slider status */
    slider_touch_info = Cy_CapSense_GetTouchInfo(
                            CY_CAPSENSE_LINEARSLIDER0_WDGT_ID, &cy_capsense_context);
    slider_touch_status = slider_touch_info->numPosition;
    slider_pos = slider_touch_info->ptrPosition->x;
    slider_pos = (slider_pos * 100) / cy_capsense_context.ptrWdConfig[CY_CAPSENSE_LINEARSLIDER0_WDGT_ID].xResolution;

    /* Detect the new touch on slider */
    if ((RT_NULL != slider_touch_status) &&
            (slider_pos != slider_pos_prev))
    {
        //rt_kprintf("slider_pos %d\n\r", slider_pos);
        //rt_kprintf("lastMsgTick %d %d\n\r", lastMsgTick, rt_tick_get());
        if((rt_tick_get() - lastMsgTick ) < 60)
        {
            if(slider_pos > slider_pos_prev)
            {
                send_cmd = HID_MEDIA_AUDIO_VOLUME_UP;
            }
            else
            {
                send_cmd = HID_MEDIA_AUDIO_VOLUME_DOWN;
            }
            send_hid_media_cmd(send_cmd);
            rt_kprintf("send_cmd %x\n\r", send_cmd);
        }
        lastMsgTick = rt_tick_get();
    }

    slider_pos_prev = slider_pos;
}

static void Slider_thread_entry(void *parameter)
{
    Slider_Init();

    for (;;)
    {
        rt_sem_take(trans_done_semphr, RT_WAITING_FOREVER);

        /* Process all widgets */
        Cy_CapSense_ProcessAllWidgets(&cy_capsense_context);

        /* Process touch input */
        process_touch();

        /* Establishes synchronized operation between the CapSense
         * middleware and the CapSense Tuner tool.
         */
        Cy_CapSense_RunTuner(&cy_capsense_context);

        /* Initiate next scan */
        Cy_CapSense_ScanAllWidgets(&cy_capsense_context);

        rt_thread_mdelay(50);
    }
}

int Slider_ctrl_init(void)
{
    rt_err_t ret = RT_EOK;

    sld_thread = rt_thread_create("slider_th",
                                  Slider_thread_entry,
                                  RT_NULL,
                                  1024,
                                  25,
                                  10);
    if (sld_thread != RT_NULL)
    {
        rt_thread_startup(sld_thread);
    }
    else
    {
        ret = -RT_ERROR;
    }

    return ret;
}

int main(void)
{

    Slider_ctrl_init();

    rt_pin_mode(LED_PIN, PIN_MODE_OUTPUT);
    for (;;)
    {
        rt_pin_write(LED_PIN, PIN_HIGH);
        rt_thread_mdelay(500);
        rt_pin_write(LED_PIN, PIN_LOW);
        rt_thread_mdelay(500);
    }
}

